<?php
/**
 * Created by PhpStorm.
 * User: s.utkin
 * Date: 18.05.2015
 * Time: 20:13
 */

namespace Pinenut;


class CombinationIterator implements \Iterator {

	protected $count = 0;
	protected $iteration = 0;
	protected $index = -1;
	protected $iteratorsInfo = null;

	public function __construct()
	{
		$this->iteratorsInfo = [];
	}

	public function addIterator(\Iterator $iterator, $key = null)
	{
		$this->count++;
		$this->index = $this->count - 1;

		$this->iteratorsInfo[] = [
			'instance' => $iterator,
			'key' => $key ?: $this->index,
		];
	}

	/**
	 * (PHP 5 &gt;= 5.0.0)<br/>
	 * Return the current element
	 * @link http://php.net/manual/en/iterator.current.php
	 * @return mixed Can return any type.
	 */
	public function current()
	{
		$current = [];

		foreach ($this->iteratorsInfo as $row) {
			/** @var \Iterator  $iterator */
			$iterator = $row['instance'];
			$current[$row['key']] = $iterator->current();
		}

		return $current;
	}

	/**
	 * (PHP 5 &gt;= 5.0.0)<br/>
	 * Move forward to next element
	 * @link http://php.net/manual/en/iterator.next.php
	 * @return void Any returned value is ignored.
	 */
	public function next()
	{
		/** @var \Iterator $currentIterator */
		$currentIterator = $this->iteratorsInfo[$this->index]['instance'];
		$currentIterator->next();

		while (!$currentIterator->valid() && $this->index > 0) {
			$currentIterator->rewind();
			$this->index--;
			$currentIterator = $this->iteratorsInfo[$this->index]['instance'];
			$currentIterator->next();
		}

		$this->index = $this->count - 1;
	}

	/**
	 * (PHP 5 &gt;= 5.0.0)<br/>
	 * Return the key of the current element
	 * @link http://php.net/manual/en/iterator.key.php
	 * @return mixed scalar on success, or null on failure.
	 */
	public function key()
	{
		$key = [];

		foreach ($this->iteratorsInfo as $row) {
			$key[$row['key']] = $this->iteration;
		}

		return $key;
	}

	/**
	 * (PHP 5 &gt;= 5.0.0)<br/>
	 * Checks if current position is valid
	 * @link http://php.net/manual/en/iterator.valid.php
	 * @return boolean The return value will be casted to boolean and then evaluated.
	 * Returns true on success or false on failure.
	 */
	public function valid()
	{
		return isset($this->iteratorsInfo[0]['instance']) &&
			$this->iteratorsInfo[0]['instance']->valid();
	}

	/**
	 * (PHP 5 &gt;= 5.0.0)<br/>
	 * Rewind the Iterator to the first element
	 * @link http://php.net/manual/en/iterator.rewind.php
	 * @return void Any returned value is ignored.
	 */
	public function rewind()
	{
		$this->index = $this->count - 1;
		$this->iteration = 0;

		foreach ($this->iteratorsInfo as $row) {
			$row['instance']->rewind();
		}
	}
}